package Arduino;

import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;


/**
 * User: Mike
 * Date: 7/29/12
 */
public class ReadSensor implements SerialPortEventListener {

    // The port to use.
    private static final String PORT_NAMES[] = {
            "/dev/tty.usbserial-A9007UX1", // Mac OS X
            "/dev/ttyUSB0", // Linux
            "COM3", // Windows
    };
    private InputStream input;                  // Buffered input stream from the port
    private OutputStream output;                // The output stream to the port
    private static final int TIME_OUT = 2000;   // Milliseconds to block while waiting for port open
    private static final int DATA_RATE = 9600;  // Default bits per second for COM port.
    private SerialPort serialPort;

    protected String lastChunk = "";
    private Measurement measurement;
    private long maxUpdateFrequency;        // this is also set in the arduino firmware code
    private long lastMeasurementTime;

    public ReadSensor(Measurement measurement, long maxUpdateFrequency) {
        this.measurement = measurement;
        this.maxUpdateFrequency = maxUpdateFrequency;
    }

    public void initialize() {
        lastMeasurementTime = 0;
        CommPortIdentifier portId = null;
        Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();

        // iterate through, looking for the port
        while (portEnum.hasMoreElements()) {
            CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
            for (String portName : PORT_NAMES) {
                if (currPortId.getName().equals(portName)) {
                    portId = currPortId;
                    break;
                }
            }
        }

        if (portId == null) {
            System.out.println("Could not find COM port.");
            return;
        }

        try {
            // open serial port, and use class name for the appName.
            serialPort = (SerialPort) portId.open(this.getClass().getName(), TIME_OUT);

            // set port parameters
            serialPort.setSerialPortParams(DATA_RATE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

            // open the streams
            input = serialPort.getInputStream();
            output = serialPort.getOutputStream();

            // add event listeners
            serialPort.addEventListener(this);
            serialPort.notifyOnDataAvailable(true);
        } catch (Exception e) {
            System.err.println(e.toString());
        }
    }

    /**
     * This should be called when you stop using the port.
     * This will prevent port locking on platforms like Linux.
     */
    public synchronized void close() {
        if (serialPort != null) {
            serialPort.removeEventListener();
            serialPort.close();
        }
    }

    /**
     * Handle an event on the serial port. Read the data and print it.
     */
    public synchronized void serialEvent(SerialPortEvent oEvent) {

        if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
            try {
                int available = input.available();
                byte chunk[] = new byte[available];
                input.read(chunk, 0, available);
                lastChunk = lastChunk + new String(chunk);

                if ((System.currentTimeMillis() - lastMeasurementTime) > maxUpdateFrequency) {
                    measurement.update();
                    lastMeasurementTime = System.currentTimeMillis();
                }
            } catch (Exception e) {
                System.err.println(e.toString());
            }
        }

        if (oEvent.getEventType() == SerialPortEvent.BI)
            System.out.println("SerialPortEvent.BI");
        if (oEvent.getEventType() == SerialPortEvent.CD)
            System.out.println("SerialPortEvent.CD");
        if (oEvent.getEventType() == SerialPortEvent.CTS)
            System.out.println("SerialPortEvent.CTS");
        if (oEvent.getEventType() == SerialPortEvent.DSR)
            System.out.println("SerialPortEvent.DSR");
        if (oEvent.getEventType() == SerialPortEvent.FE)
            System.out.println("SerialPortEvent.FE");
        if (oEvent.getEventType() == SerialPortEvent.OE)
            System.out.println("SerialPortEvent.OE");
        if (oEvent.getEventType() == SerialPortEvent.PE)
            System.out.println("SerialPortEvent.PE");
        if (oEvent.getEventType() == SerialPortEvent.RI)
            System.out.println("SerialPortEvent.RI");
        if (oEvent.getEventType() == SerialPortEvent.OUTPUT_BUFFER_EMPTY)
            System.out.println("SerialPortEvent.OUTPUT_BUFFER_EMPTY");

    }

    public String getLastChunk() {
        return lastChunk;
    }

    public void setLastChunk(String lastChunk) {
        this.lastChunk = lastChunk;
    }
}
